package com.fun.fun.frame.excute;

import com.fun.frame.Save;
import com.fun.frame.SourceCode;
import com.fun.frame.utils.Output;
import com.fun.httpclient.ClientManage;
import com.fun.httpclient.FanLibrary;
import com.fun.profile.Constant;
import com.fun.utils.Time;
import com.fun.utils.WriteRead;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Concurrent extends FanLibrary {

    /**
     * 请求
     */
    public HttpRequestBase request;

    /**
     * 线程数，多请求等于请求数
     */
    public int threads;

    /**
     * 线程请求执行次数
     */
    public int times;

    /**
     * 多个请求集合
     */
    public List<HttpRequestBase> requests;

    /**
     * 用于记录每次多线程执行的响应时间
     */
    public static Vector<Long> allTimes = new Vector<>();

    /**
     * 多请求单线程多次请求方法
     *
     * @param requests 请求列表
     * @param times    单个请求的请求次数
     */
    public Concurrent(List<HttpRequestBase> requests, int times) {
        this.requests = requests;
        this.times = times;
        this.threads = requests.size();
    }

    /**
     * 单请求多线程多次任务构造方法
     *
     * @param request 被执行的请求
     * @param threads 线程数
     * @param times   每个线程运行的次数
     */
    public Concurrent(HttpRequestBase request, int threads, int times) {
        this.request = request;
        this.threads = threads;
        this.times = times;
    }

    /**
     * 执行多线程任务
     */
    public void excuteTreads() {
        ExecutorService executorService = Executors.newFixedThreadPool(threads);//新建定长线程池
        CountDownLatch countDownLatch = new CountDownLatch(threads);//新建一个CountDownLatch处理线程关闭，长度等于线程池长度
        long start = Time.getTimeStamp();
        for (int i = 0; i < threads; i++) {
            executorService.execute(new More(countDownLatch, getRequest(i)));
        }
        try {
            countDownLatch.await();
            executorService.shutdown();
        } catch (InterruptedException e) {
            Output.output("线程池关闭失败！", e);
        }
        long end = Time.getTimeStamp();
        Save.saveLongList(allTimes, threads);
        countQPS(threads);
        output("总计" + threads + "个线程，总计" + (threads * times) + "次请求，共用时：" + Time.getTimeDiffer(start, end) + "秒！");
    }

    /**
     * 获取请求
     *
     * @param i 个
     * @return
     */
    private HttpRequestBase getRequest(int i) {
        if (requests == null)
            return request;
        return requests.get(i);
    }

    /**
     * 计算结果
     *
     * @param name
     */
    public static void countQPS(int name) {
        List<String> strings = WriteRead.readTxtFileByLine(Constant.LONG_Path + name + Constant.FILE_TYPE_LOG);
        int size = strings.size();
        output("数据量：" + size);
        double sum = 0;
        for (int i = 0; i < size; i++) {
            double time = SourceCode.changeStringToInt(strings.get(i));
            sum += time;
        }
        Output.output("时间总和：" + sum);
        double v = 1000 / sum * size * name;
        Output.output("QPS：" + v);
    }

    /**
     * 多次执行某个请求，但是不记录日志，记录方法用 loglong
     * <p>此方法只适应与单个请求的重复请求，对于有业务联系的请求暂时不能适配</p>
     *
     * @param request 请求
     * @param times   次数
     */
    static void executeRequest(HttpRequestBase request, int times) {
        List<Long> testTimes = new ArrayList<>();
        FanLibrary.beforeRequest(request);
        long start1 = Time.getTimeStamp();
        for (int i = 0; i < times; i++) {
            double elapsed_time = 0.0;
            CloseableHttpResponse response = null;// 创建响应对象
            long start = Time.getTimeStamp();
            try {
                response = ClientManage.httpsClient.execute(request);
            } catch (IOException e1) {
                output(e1);
            }
            long end = Time.getTimeStamp();// 记录结束时间
            long time = end - start;
            try {
                if (response != null) response.close();
            } catch (Exception e2) {
                output("响应关闭失败！", e2);
            }
            output(3);
            testTimes.add(time);
        }
        long end1 = Time.getTimeStamp();
        allTimes.addAll(testTimes);
    }

    /**
     * 多线程类
     */
    class More implements Runnable {

        private CountDownLatch countDownLatch;

        private HttpRequestBase request;

        public More(CountDownLatch countDownLatch, HttpRequestBase request) {
            this.countDownLatch = countDownLatch;
            this.request = request;
        }

        @Override
        public void run() {
            try {
                executeRequest(request, times);
            } finally {
                countDownLatch.countDown();
            }
        }

    }

}